import EventCenter from './eventCenter'
/**
 * @description 封装socket连接
 * @author zhangming
 * @createTime 2022/05/17
 * @param { String } url socket 连接的url
 * @param { Number } time 心跳检测间隔时间
 */
class WSRequest {
    constructor(url, time = 4000) {
        this.status = 0; // websocket是否关闭 // 0 未连接 1 已连接
        this.lockReconnect = false; //避免重复连接
        this.url = url; // socket 连接地址
        this.eventCenter = new EventCenter() // 消息订阅中心

        //心跳检测
        this.timeout = time; //多少秒执行检测
        this.timeoutObj = null; //检测服务器端是否还活着
        this.reconnectTimeOutObj = null; //重连之后多久再次重连
        this.socketTask = null; // socket实例
    }
    /**
     * @desc 尝试建立 socket 连接 出错自动重连
     * @returns { undefined }
     */
    startConnect () {
        try {
            return this.initRequest();
        } catch (e) {
            console.log("catch", e);
            this.reconnect();
        }
    }
    initRequest() {
        this.socketTask = uni.connectSocket({
            url: this.url, //接口地址。
            success: () => {
                console.log("连接成功");
                // 返回实例
                return this.socketTask;
            },
        });

        this.socketTask.onOpen((res) => {
            console.log(res, "连接打开");
            this.status = 1
            // 清除重连定时器
            clearTimeout(this.reconnectTimeOutObj);
            // 开启检测
            this.start();
        });

        // 如果希望websocket连接一直保持，在close或者error上绑定重新连接方法。
        this.socketTask.onClose((res) => {
            this.status = 0
            console.log(res, "连接关闭");
            // this.reconnect();
        });

        this.socketTask.onError((res) => {
            console.log(res, "连接错误");
            this.status = 0
            this.reconnect();
        });

        this.socketTask.onMessage((res) => {
            // 需要处理事件的发布订阅
            this.handleMessage(res) // 处理消息
            // 接受任何消息都说明当前连接是正常的
            console.log(res, "pong");
            this.reset();
        });
    }
    /**
     * @desc 发送消息
     * @param { any } value 发送的消息体 
     * @returns { Promise }
     */
    send(value) {
        return new Promise((resovle, reject) => {
            this.socketTask.send({
                data: value,
                success: () => {
                    resovle("发送成功");
                },
                fail: reject
            });
        });
    }

    // reset和start方法主要用来控制心跳的定时。
    reset() {
        // 清除定时器重新发送一个心跳信息
        clearTimeout(this.timeoutObj);
        this.start();
    }
    // 开始触发心跳
    start() {
        this.timeoutObj = setTimeout(() => {
            //这里发送一个心跳，后端收到后，返回一个心跳消息，
            //onmessage拿到返回的心跳就说明连接正常
            console.log("ping");
            this.socketTask.send({ data: "ping" });
        }, this.timeout);
    }

    // 重连
    reconnect() {
        // 防止多个方法调用，多处重连
        if (this.lockReconnect) return;
        this.lockReconnect = true;
        console.log("准备重连");
        //没连接上会一直重连，设置延迟避免请求过多
        this.reconnectTimeOutObj = setTimeout(() => {
            // 重新连接
            this.initRequest();
            this.lockReconnect = false;
        }, 4000);
    }

    // 手动关闭
    close() {
        this.socketTask.close();
    }
    handleMessage (message) {
        const { eventName } = message || {}
        // 派发事件
        this.eventCenter.dispatch(eventName, message)
    }
}

/**
 * @desc 静态方法，闭包保证获取到的是一个单例
 * @returns 
 */
WSRequest.getInstance = (function () {
    let instance = null
        return function () {
            if (!instance) instance = new WSRequest()
            return instance
        }
})()

export default WSRequest.getInstance();


/**
 * @example 
 */
/** main.js */
// // 引入
// import wsSocket from './socket.js'
// // 挂在到原型上
// Vue.prototype.$wsSocket = wsSocket

// export default {
    // 页面使用
    // onShow () {
    //     if (this.$wsSocket.status !== 1) {
    //         // socket 未连接的情况下 连接 socket
    //         this.$wsSocket.startConnect()
    //     }
    //     /** 订阅当前页面所需要的事件 */
    //     this.$wsSocket.eventCenter.subscribe('xxxxx', this.eventHandler)
    // },
    // methods: {
    //     eventHandler (message) {
    //         // do something
    //     }
    // }

// }
